﻿//
// *************************************************************************************
// WP-Framework
// 
// Developed by
// Lukas Kretschmar (lkretschmar.dev@bluewin.ch)
//
// Switzerland, Copyright (c) 2013 lkretschmar
// This content is released under the MIT License (http://opensource.org/licenses/MIT).
//     
// *************************************************************************************
//
//
			

using System.Collections.Generic;
using System.Linq;
using KretschIT.WP_Fx.Core.Validation;
using System.Diagnostics;
using System;

namespace KretschIT.WP_Fx.UI.Commands
{
    public class CommandManager : ICommandManager
    {
        #region Singleton

        private static ICommandManager instance;

        public static ICommandManager Current
        {
            get { return instance ?? (instance = new CommandManager()); }
        }

        internal static void Clear()
        {
            instance = null;
        }

        private CommandManager() { }

        #endregion

        #region Registration

        private readonly Dictionary<object, IList<IRelayCommand>> registrations = new Dictionary<object, IList<IRelayCommand>>();

        public void Register(object obj, IRelayCommand command)
        {
            It.IsNotNull(() => obj);
            It.IsNotNull(() => command);
            this.Add(command, obj);
        }

        private void Add(IRelayCommand command, object obj)
        {
            IList<IRelayCommand> commands = null;
            if (!this.registrations.ContainsKey(obj))
            {
                commands = new List<IRelayCommand>();
                this.registrations.Add(obj, commands);
            }
            else
            {
                commands = this.registrations[obj];
            }

            if (!commands.Contains(command))
            {
                commands.Add(command);
            }
        }

        public void Unregister(object obj)
        {
            if (obj == null)
            {
                return;
            }
            this.registrations.Remove(obj);
        }

        public void Unregister(IRelayCommand command)
        {
            foreach (var coll in this.registrations.Values)
            {
                coll.Remove(command);
            }
        }

        #endregion

        #region Refresh

        public void RefreshAll()
        {
            this.RaiseCanExecuteChangedFor(this.registrations.Values.SelectMany(v => v).Distinct());
        }

        public void Refresh(object obj)
        {
            if (obj == null)
            {
                return;
            }
            if (this.registrations.ContainsKey(obj))
            {
                this.RaiseCanExecuteChangedFor(this.registrations[obj]);
            }
        }

        public void Refresh<T>()
        {
            foreach (var obj in this.registrations.Keys.OfType<T>())
            {
                this.RaiseCanExecuteChangedFor(this.registrations[obj]);
            }
        }

        private void RaiseCanExecuteChangedFor(IEnumerable<IRelayCommand> commands)
        {
            foreach (var command in commands)
            {
                try
                {
                    command.RaiseCanExecuteChanged();
                }
                catch(Exception ex)
                {
                    Debug.WriteLine("Command threw exception! Type: {0} - Message: {1}", ex.GetType().Name, ex.Message);
                }
            }
        }

        #endregion
    }
}
